use nom::branch::alt;
use nom::bytes::complete::{tag, tag_no_case, take_while1};
use nom::character::complete::{digit1, one_of};
use nom::combinator::{map, map_res, opt, recognize, value};
use nom::multi::many1;
use nom::sequence::{pair, preceded, separated_pair, terminated};
use nom::IResult;

fn measurement(input: &str) -> IResult<&str, &str> {
    // many1至少存在一个
    recognize(many1(alt((
        tag("\\ "),
        tag("\\,"),
        tag("\\,"),
        take_while1(|c: char| c != ' ' && c != ',' && c != '\\'),
    ))))(input)
}

fn tag_key_value(input: &str) -> IResult<&str, &str> {
    // many1至少存在一个
    // alt按顺序执行，所以tag("\\=,"),要放在tag("\\,"),前面
    recognize(many1(alt((
        tag("\\ "),
        tag("\\,"),
        tag("\\=,"),
        tag("\\,"),
        // recognize(none_of(" ,\\="))// 识别除了空格、逗号、反斜杠、等号之外的字符 一个字符一个字符的识别，效率较低，推荐使用take_while1
        take_while1(|c: char| c != ' ' && c != ',' && c != '\\' && c != '='),
    ))))(input)
}

fn tag_set(input: &str) -> IResult<&str, Vec<(&str, &str)>> {
    // many1至少存在一个
    // alt按顺序执行，所以tag("\\=,"),要放在tag("\\,"),前面
    many1(preceded(
        tag(","),
        separated_pair(tag_key_value, tag("="), tag_key_value),
    ))(input)
}

#[derive(Debug, Clone)]
pub enum FieldValue<'a> {
    Bool(bool),
    Int(i64),
    Uint(u64),
    Float(f64),
    String(&'a str),
}

fn bool_value(input: &str) -> IResult<&str, FieldValue> {
    alt((
        value(FieldValue::Bool(true), tag_no_case("true")),
        value(FieldValue::Bool(false), tag_no_case("false")),
        value(FieldValue::Bool(true), tag_no_case("t")),
        value(FieldValue::Bool(false), tag_no_case("f")),
    ))(input)
}

fn int_value(input: &str) -> IResult<&str, FieldValue> {
    map(
        terminated(
            map_res(recognize(pair(opt(one_of("+-")), digit1(input))), |&str| {
                let number = str.parse::<i64>();
            }),
            tag("i"),
        ),
        |n| FieldValue::Int(n),
    )(input)
}

fn uint_value(input: &str) -> IResult<&str, FieldValue> {
    alt((
        (FieldValue::Uint(0), tag("0")),
        value(FieldValue::Uint(1), tag("1")),
    ))(input)
}

fn float_value(input: &str) -> IResult<&str, FieldValue> {
    alt((
        value(FieldValue::Float(0.0), tag("0.0")),
        value(FieldValue::Float(1.0), tag("1.0")),
    ))(input)
}

fn string_value(input: &str) -> IResult<&str, FieldValue> {
    alt((
        value(FieldValue::String("0"), tag("0")),
        value(FieldValue::String("1"), tag("1")),
    ))(input)
}

fn field_value(input: &str) -> IResult<&str, FieldValue> {
    alt((bool_value, int_value, uint_value, float_value, string_value))(input)
}

#[test]
fn test_measurement() {
    let input = "\\ \\ \\ \\ \\";
    assert_eq!(measurement("气温"), Ok(("", "气温")));
    assert_eq!(measurement("气温 hello"), Ok((" hello", "气温")));
    assert_eq!(measurement("气温,hello"), Ok((",hello", "气温")));
}
